﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UFPE.CIn.Abc.Primality.Util;
using System.Diagnostics;

namespace UFPE.CIn.Abc.Primality.Algorithms
{
    public abstract class BaseConfidenceAlgorithm : IAlgorithm
    {
        private long timeLastRun;

        protected Stopwatch cron;

        public abstract bool IsPrime(BigInteger x);

        public bool IsPrime(BigInteger x, int conf)
        {
            return IsPrime(x, conf, false);
        }

        public abstract bool IsPrime(BigInteger x, bool trialDivisionFirst2kPrimes);

        public bool IsPrime(BigInteger x, int confidence, bool trialDivisionFirst2kPrimes)
        {
            cron = Stopwatch.StartNew();

            BigInteger thisVal = x.AbsoluteValue();

            switch (thisVal.PreliminaryChecks())
            {
                case BigInteger.Status.None:
                case BigInteger.Status.Composite:
                    cron.Stop();
                    timeLastRun = cron.ElapsedMilliseconds;
                    return false;
                case BigInteger.Status.Prime:
                    cron.Stop();
                    timeLastRun = cron.ElapsedMilliseconds;
                    return true;
            }

            if (trialDivisionFirst2kPrimes)
            {
                for (int p = 0; p < BigInteger.primesBelow2000.Length; p++)
                {
                    BigInteger divisor = BigInteger.primesBelow2000[p];

                    if (divisor >= thisVal)
                        break;

                    BigInteger resultNum = thisVal % divisor;
                    if (resultNum.IntValue() == 0)
                    {
                        return false;
                    }
                }
            }

            bool returnValue = Helper(thisVal, confidence);

            cron.Stop();
            timeLastRun = cron.ElapsedMilliseconds;

            return returnValue;
        }

        public abstract bool Helper(BigInteger thisVal, int confidence);

        public abstract string AlgorithmName
        {
            get;
        }

        public long TimeLastRun
        {
            get { return timeLastRun; }
        }

        public long Threshold
        {
            get
            {
                return 0;
            }
        }
    }
}
